/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ru.icq.io;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.spec.InvalidKeySpecException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import ru.icq.exceptions.CryptExceptions;
import ru.icq.exceptions.errors.CryptError;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
* Класс реализующий работу с алгоритмом шифрования DES
* @author Носов А.В.
*/
public class DesEncrypter {

    // Variables declaration
    String algorithm = "DESede";
    // End of variables declaration

    public DesEncrypter() {
    }

    /**
    * Функция шифровния
    * @param str строка открытого текста
    * @return зашифрованная строка в формате Base64
    */
    public String encrypt(String str) throws CryptExceptions {
        try {
            byte[] utf8 = str.getBytes("UTF8");
        
            SecretKey ekey = KeyGenerator.getInstance(algorithm).generateKey();
            Cipher ecipher = Cipher.getInstance(algorithm);
            ecipher.init(Cipher.ENCRYPT_MODE, ekey);

            byte[] enc = ecipher.doFinal(utf8);
            SecretKeyFactory skf = SecretKeyFactory.getInstance(algorithm);
            DESedeKeySpec keyspec = (DESedeKeySpec) skf.getKeySpec(ekey, DESedeKeySpec.class);
            byte[] bkey = keyspec.getKey();
            String skey = new BASE64Encoder().encode(bkey);
            return ((new BASE64Encoder().encode(enc)) + "|" + skey);
        } catch (UnsupportedEncodingException ex) {
            throw new CryptExceptions(CryptError.EMPTY_NOT_SUPPORTED);
        } catch (IllegalBlockSizeException ex) {
            throw new CryptExceptions(CryptError.EMPTY_BLOCK_INCORRECT);
        } catch (BadPaddingException ex) {
            throw new CryptExceptions((CryptError.EMPTY_ERROR_INPUT_DATA));
        } catch (NoSuchAlgorithmException ex) {
            throw new CryptExceptions(CryptError.EMPTY_NO_ALGORITHM);
        } catch (InvalidKeySpecException ex) {
            throw new CryptExceptions(CryptError.EMPTY_INVALID_KEY);
        } catch (InvalidKeyException ex) {
            throw new CryptExceptions(CryptError.EMPTY_INVALID_KEY);
        } catch (NoSuchPaddingException ex) {
            throw new CryptExceptions(CryptError.EMPTY_NO_ALGORITHM);
        }
    }

    /**
    * Функция расшифрования
    * @param str зашифрованная строка в формате Base64
    * @return расшифрованная строка
    */
    public String decrypt(String str) throws CryptExceptions {
        try {
            String[] s = new String[2];
            s[0] = str.substring(0, str.indexOf("|"));
            s[1] = str.substring(str.indexOf("|")+1);
            SecretKeyFactory skf = SecretKeyFactory.getInstance(algorithm);
            DESedeKeySpec keyspec = new DESedeKeySpec(new BASE64Decoder().decodeBuffer(s[1]));
            SecretKey dkey = skf.generateSecret(keyspec);

            Cipher dcipher = Cipher.getInstance(algorithm);
            dcipher.init(Cipher.DECRYPT_MODE, dkey);
            byte[] dec = new BASE64Decoder().decodeBuffer(s[0]);
            byte[] utf8 = dcipher.doFinal(dec);
            return new String(utf8, "UTF8");
        } catch (IllegalBlockSizeException ex) {
            throw new CryptExceptions(CryptError.EMPTY_BLOCK_INCORRECT);
        } catch (BadPaddingException ex) {
            throw new CryptExceptions((CryptError.EMPTY_ERROR_INPUT_DATA));
        } catch (InvalidKeyException ex) {
            throw new CryptExceptions(CryptError.EMPTY_INVALID_KEY);
        } catch (NoSuchAlgorithmException ex) {
            throw new CryptExceptions(CryptError.EMPTY_NO_ALGORITHM);
        } catch (InvalidKeySpecException ex) {
            throw new CryptExceptions(CryptError.EMPTY_INVALID_KEY);
        } catch (NoSuchPaddingException ex) {
            throw new CryptExceptions(CryptError.EMPTY_NO_ALGORITHM);
        } catch (IOException ex) {
            throw new CryptExceptions(CryptError.EMPTY_IO);
        }
    }
    
    /**
    * Функция для проверки правильности работы класса
    */
    public static void main(String[] s) throws CryptExceptions{
//        SecretKey key=null;
//        key = KeyGenerator.getInstance("DES").generateKey();
        DesEncrypter encrypter = new DesEncrypter();
        String OStr1="Kakoi takoi secret";
        String SStr = encrypter.encrypt(OStr1);
        String OStr2 = encrypter.decrypt(SStr);
        System.out.println("Open String: "+OStr1+
        "\nAfter encripting: "+SStr+"\nAfter decripting: "+OStr2);
    }
}
